import { RVOMath } from "./RVO2/RVOMath";
import { Simulator } from "./RVO2/Simulator";
import { Vector2 } from "./RVO2/Vector2";

const { ccclass, property } = cc._decorator;

@ccclass
export default class Game extends cc.Component {

    private sim: Simulator = new Simulator();

    @property(cc.Node)
    player: cc.Node = null;

    private goals: Vector2[] = [];

    private targetPos: Vector2 = null;

    private players: cc.Node[] = [];

    @property(cc.Node)
    map: cc.Node = null;
    private setupScenario() {
        this.sim.setTimeStep(0.5);
        this.sim.setAgentDefaults(
            125,//在寻找周围邻居的搜索距离，这个值设置越大，会让小球在越远距离做出避障行为
            20,//寻找周围邻居的最大数目，这个值设置越大，最终计算的速度越 精确，但会加大计算量
            100,//计算动态的物体时的时间窗口
            0,//代表计算静态的物体时的时间窗口，比如在RTS游戏中，小兵 向城墙移动时，没必要做出避障，这个值需要设置的很小
            this.player.width / 2,//代表计算ORCA时的小球的半径，这个值不一定与小球实际显示的半径 一样，偏小有利于小球移动顺畅
            2,//小球最大速度值
            // new Vector2(1,1)
        );
    }

    private initPlayer() {
        for (let i = 0; i < this.map.childrenCount; i++) {
            this.players.push(this.map.children[i]);
        }
    }

    private deletePlayer(player: cc.Node) {
        let index = this.players.indexOf(player)
        if (index != -1) {
            this.players.splice(index, 1)
        }
    }

    private addObstacle() {

        //添加四边墙的障碍物
        let wall: Vector2[] = [];

        let width = this.map.width;
        let height = this.map.height;

        //限制最外层不能出屏幕,管方说明按逆时针方向
        wall.push(new Vector2(width, 0));//右下
        wall.push(new Vector2(0, 0)); //左下
        wall.push(new Vector2(0, height));//左上
        wall.push(new Vector2(width, height));//右上

        //添加中间的阻挡
        let other: Vector2[] = [];
        let left_top = cc.find("obs/left_top", this.node);
        let left_down = cc.find("obs/left_down", this.node);
        let right_top = cc.find("obs/right_top", this.node);
        let right_down = cc.find("obs/right_down", this.node);

        other.push(new Vector2(right_top.x, right_top.y));
        other.push(new Vector2(left_top.x, left_top.y));
        other.push(new Vector2(left_down.x, left_down.y));
        other.push(new Vector2(right_down.x, right_down.y));

        // this.sim.addObstacle(other);

        this.sim.addObstacle(wall);

        this.sim.processObstacles();
    }

    onLoad() {
        this.setupScenario();

        this.initPlayer();

        this.updateAgent();

        this.addObstacle();

        this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
    }

    private onTouchEnd(ev: cc.Event.EventTouch) {
        let pos = ev.getLocation();
        pos = this.map.convertToNodeSpaceAR(pos);
        this.targetPos = new Vector2(pos.x, pos.y);
    }

    /**@description 更新当前所有代理点的位置 */
    private updatePositon() {
        for (let i = 0; i < this.sim.getNumAgents(); i++) {
            let pos = this.sim.getAgentPosition(i);
            this.players[i].x = pos.x;
            this.players[i].y = pos.y;
        }
    }

    /**@description 设置当前各代理点的行进方向 */
    private setPreferrenVelocities() {

        for (let i = 0; i < this.players.length; i++) {
            if (this.targetPos) {
                this.goals[i] = new Vector2(this.targetPos.x, this.targetPos.y);
            } else {
                this.goals[i] = new Vector2(this.map.width / 2, this.map.height / 2);
            }
        }

        for (let i = 0; i < this.sim.getNumAgents(); i++) {
            let vec = this.goals[i].moins(this.sim.getAgentPosition(i));
            let distance =Vector2.absSq(vec);
            if ( distance > this.sim.getAgentRadius(i) * this.sim.getAgentRadius(i)) {
                vec = Vector2.normalize(vec);
                vec = vec.mul_k(2);
            } else {
                vec.x = 0;
                vec.y = 0;
            }
            this.sim.setAgentPrefVelocity(i, vec);
        }
    }

    update() {
        this.updatePositon();
        this.setPreferrenVelocities();
        this.sim.doStep()
        
    }


    private updateAgent() {
        this.goals = [];
        this.sim.clear();
        for (let i = 0; i < this.players.length; i++) {
            let pos = new Vector2(this.players[i].x, this.players[i].y);
            this.sim.addAgent(pos);
            if (i == 2) {
                this.sim.setAgentRadius(i, this.player.width);
                this.sim.setAgentMaxSpeed(i, 2);
            }
            this.sim.setAgentMaxSpeed(i, 2.5 + Math.random() * 1);
            this.goals.push(pos);
        }
    }

    onDelete() {
        let player = cc.find("player1", this.map);
        if (player) {
            this.deletePlayer(player);
            this.updateAgent();
            this.addObstacle();
        }
    }
}
